/***************************************************************************
 *   Copyright (C) 2007 by Ziman & Xloverin                                *
 *   ziman@centrum.sk, xloverin@gmail.com                                  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <QMessageBox>

#include "query.h"
#include "core.h"
#include "prefslog.h"
#include "terminal.h"

const QString Query::hlIcons[3] = {
	":/activity/ball_gray.xpm",
	":/activity/ball_green.xpm",
	":/activity/ball_red.xpm"
};

void Query::setHilightLevel(Query::HilightLevel level)
{
	m_core->setHilightLevel(this, level);
}

void Query::releaseInput()
{
	if (m_core->inputCapture() != this) {
		qDebug("A query tried to release non-captured input. Ignoring silently.");
		return;
	}

	m_core->setInputCapture(0);
}

void Query::captureInput()
{
	m_core->setInputCapture(this);
}

void Query::logLine(const Line &line)
{
	Log *log = m_core->log();
	Log::Prefs logPrefs = m_core->preferences().log;

	// Plaintext
	if (logPrefs.format & PrefsLog::Plaintext) {
		log->write(m_prefs.title, PrefsLog::Plaintext, line.plain(), m_terminal);
	}

	// VT100
	if (logPrefs.format & PrefsLog::Vt100) {
		log->write(m_prefs.title, PrefsLog::Vt100, QString::fromLocal8Bit(line.binary()), m_terminal);
	}

	// MonoHTML
	if (logPrefs.format & PrefsLog::PlainHtml) {
		log->write(m_prefs.title, PrefsLog::PlainHtml, Terminal::interpretVt100(line.binary(), Terminal::MonoHtml), m_terminal);
	}

	// HTML
	if (logPrefs.format & PrefsLog::Html) {
		log->write(m_prefs.title, PrefsLog::Html, Terminal::interpretVt100(line.binary(), Terminal::Html), m_terminal);
	}

}

void Query::processLine(const Line &line, bool lineMode)
{
	// TODO Zriesit hilighty
	setHilightLevel(Active);

	if (lineMode) logLine(line);

	switch (captureState) {
		case Normal:
			if (line.tag().type == Line::Hug) {
				captureInput();
				captureState = Hug;
			}
			break;

		default:
			break;
	}

	if (lineMode && m_core->preferences().appearance.showTimestamps) {
		m_terminal->write((Log::format(m_core->preferences().appearance.timestampFormat, m_prefs.title) + " ").toAscii(), lineMode);
	} 
	
	if (lineMode && m_core->preferences().appearance.showTags) {
		m_terminal->write(
			QString("%1 %2 ")
				.arg(Line::typeNames[line.tag().type])
				.arg(QString::number(line.tag().subtype), 2)
				.toAscii(),
			lineMode
		);	
	}
	
	if (line.tag().type == Line::Tell && line.tag().subtype == 0) {
		lastTellFrom = line.tag().arg[0];
		qDebug() << "Tell od: " << lastTellFrom;
	}
	
	m_terminal->write(line.binary(), lineMode);
}

bool Query::accepts(const Line &line)
{
	const QString &rawLine = line.plain();
	
	switch (captureState) {
		case Normal:
			return (acceptRE.indexIn(rawLine) != -1);

		case Hug:
			if (line.tag().type == Line::Hug) {
				captureState = Normal;
				releaseInput();
				return true;
			} else {
				captureState = Normal;
				releaseInput();
				return false;
			}
	}

	return false;
}

QString safeEscape(QString line)
{
	line.replace("\\", "\\\\");
	return line;
}

void Query::onTerminalLineSubmitted(QString line)
{
	m_core->onUserActivity();
	
	sendLine(line);
}

bool Query::isMacro(QString line)
{
	return m_core->macroDefined(line.section(' ', 0, 0));
}

void Query::sendLine(QString line)
{
	// Local echo
	if (m_core->readMode() == Core::rmChar && m_terminal->getEcho()) {
		m_terminal->write(QString(line + "\n").toAscii(), true);
	}
	
	// reply, Issue 49
	if (line.size() > 1 && line[0] == ':') switch (line[1].toAscii()) {
		case '-': case ')': case '(': break; // vylucit smajliky
		default:
			line.remove(0, 1);
			line = ".reply " + line;
	}
	
	// reply, Issue 49
	if (line.startsWith(".reply ")) {
			if (lastTellFrom == "") {
				QString msg = tr("Nobody has ever told you anything in this query.\n");
				stripDiacritics(msg);
 				m_terminal->write(msg.toAscii(), false);
				return;
			}
			line = ".tell " + lastTellFrom + " " + line.section(' ', 1);
	}
	
	if (line.startsWith(".") || line.startsWith("<") || line.trimmed().size() == 0 || isMacro(line)) {
		m_core->getConnection()->write(line + "\r\n");
	} else {
		if (m_prefs.prefix != "") {
			/* Piseme niekomu na kver, treba to eskejpovat */
			line = safeEscape(line);
		}
		m_core->getConnection()->write(m_prefs.prefix + line + "\r\n");
	}
}

Terminal *Query::terminal()
{
	return m_terminal;
}

Query::Prefs Query::prefs()
{
	return m_prefs;
}

Query::Query(Prefs prefs, Terminal *terminal, Core *core)
{
	m_prefs = prefs;
	m_terminal = terminal;
	m_core = core;
	captureState = Normal;
	acceptRE.setCaseSensitivity(Qt::CaseInsensitive);
	acceptRE.setPatternSyntax(QRegExp::RegExp2);
	acceptRE.setPattern(prefs.acceptRE);
	terminal->setQuery(this);

	connect(terminal, SIGNAL(lineSubmitted(QString)), this, SLOT(onTerminalLineSubmitted(QString)));
}


Query::~Query()
{
	// Ak nahodou mame capturovany vstup, uvolnime ho
	if (m_core->inputCapture() == this) m_core->setInputCapture(0);
	if (m_terminal) m_terminal->closeTerminal();
}


